/**
 * Copyright (c) 2012-2014 All Rights Reserved.
 */
package com.easy.framwork.config;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import com.easy.framwork.Interceptor;
import com.easy.framwork.Plugin;
import com.easy.framwork.exceptions.ConfigException;
import com.easy.framwork.utils.ReflectUtils;
import com.easy.framwork.utils.ResourceUtils;
import com.easy.framwork.utils.StringUtils;

/**
 * 
 * @author wy
 * @version v 0.1 2014-1-5 下午10:16:39 wy Exp $
 */
public class LoadSystemConfig {

    private final static Logger log = LoggerFactory.getLogger(LoadSystemConfig.class);

    /** 配置文件 */
    private final String config;

    /**
     * 
     * @param config
     */
    public LoadSystemConfig(String config) {
        this.config = config;
    }

    /**
     * 初始化配置
     * 
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SystemConfig config() throws ParserConfigurationException, SAXException, IOException {

        SystemConfig sc = new SystemConfig();

        LinkedHashMap<String, String> constantsMap = new LinkedHashMap<String, String>();
        sc.setConstantsMap(constantsMap);
        List<InterceptorConfig> interceptors = new ArrayList<InterceptorConfig>();
        sc.setInterceptors(interceptors);

        List<PluginConfig> plugins = new ArrayList<PluginConfig>();
        sc.setPlugins(plugins);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //设置验证
        factory.setValidating(true);
        //由于我们只关心非空白元素，这里再加一条设置：
        //factory.setIgnoringElementContentWhitespace(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        builder.setErrorHandler(new ErrorHandler() {
            @Override
            public void warning(SAXParseException exception) throws SAXException {
                log.warn("解析xml-warning", exception);
            }

            @Override
            public void error(SAXParseException exception) throws SAXException {
                log.warn("解析xml-error", exception);
                throw new ConfigException("解析command.xml错误" + exception.getLineNumber() + "行,"
                                          + exception.getColumnNumber() + "列");
            }

            @Override
            public void fatalError(SAXParseException exception) throws SAXException {
                log.warn("解析xml-fatalError", exception);
            }
        });
        Document doc = builder.parse(ResourceUtils.getFile("classpath:" + config));
        doc.normalize();
        Element root = doc.getDocumentElement();
        String devMode = root.getAttribute("devMode");

        sc.setDevMode("true".equalsIgnoreCase(devMode));

        NodeList commandList = root.getElementsByTagName("constant");
        int length = commandList.getLength();
        for (int i = 0; i < length; i++) {
            Element element = (Element) commandList.item(i);
            String name = element.getAttribute("name");
            String value = element.getAttribute("value");
            if (StringUtils.isBlank(name)) {
                throw new ConfigException("第" + (i + 1) + "个constant节点的name不能为空!");
            } else if (StringUtils.isBlank(value)) {
                throw new ConfigException("第" + (i + 1) + "个constant节点的value不能为空!");
            }
            constantsMap.put(name, value);
        }
        log.info("初始化constant节点数量{}个", length);

        NodeList pluginsList = root.getElementsByTagName("plugins");
        if (pluginsList != null && pluginsList.getLength() > 0) {
            NodeList pluginList = pluginsList.item(0).getChildNodes();
            length = pluginList.getLength();
            PluginConfig pluginConfig = null;
            for (int i = 0; i < length; i++) {
                Element element = (Element) pluginList.item(i);
                String name = element.getAttribute("name");
                String className = element.getAttribute("class");
                if (StringUtils.isBlank(name)) {
                    throw new ConfigException("第" + (i + 1) + "个plugin节点的name不能为空!");
                } else if (StringUtils.isBlank(className)) {
                    throw new ConfigException("第" + (i + 1) + "个plugin节点的class不能为空!");
                }
                Class clazz = ReflectUtils.forName(className);
                if (!Plugin.class.isAssignableFrom(clazz) || clazz.isInterface()) {
                    throw new ConfigException("第" + (i + 1) + "个plugin节点的class必须实现Plugin接口!");
                }

                Plugin p = (Plugin) ReflectUtils.newInstance(clazz);
                pluginConfig = new PluginConfig();
                pluginConfig.setName(name);
                pluginConfig.setPlugin(p);
                pluginConfig.setPluginClass((Class<? extends Plugin>) clazz);
                plugins.add(pluginConfig);
                log.info("初始化plugin[name={},clazz={}]完毕", name, className);
            }
            log.info("初始化plugin节点数量{}个", length);
        }

        NodeList interceptorsList = root.getElementsByTagName("interceptors");
        if (interceptorsList != null && interceptorsList.getLength() > 0) {
            NodeList interceptorList = interceptorsList.item(0).getChildNodes();
            length = interceptorList.getLength();
            InterceptorConfig interceptorConfig = null;
            for (int i = 0; i < length; i++) {
                Element element = (Element) interceptorList.item(i);
                String name = element.getAttribute("name");
                String className = element.getAttribute("class");
                String path = element.getAttribute("path");
                if (StringUtils.isBlank(name)) {
                    throw new ConfigException("第" + (i + 1) + "个interceptor节点的name不能为空!");
                } else if (StringUtils.isBlank(className)) {
                    throw new ConfigException("第" + (i + 1) + "个interceptor节点的class不能为空!");
                } else if (StringUtils.isBlank(path)) {
                    throw new ConfigException("第" + (i + 1) + "个interceptor节点的path不能为空!");
                }
                Class clazz = ReflectUtils.forName(className);
                if (!Interceptor.class.isAssignableFrom(clazz) || clazz.isInterface()) {
                    throw new ConfigException("第" + (i + 1)
                                              + "个interceptor节点的class必须实现Interceptor接口!");
                }

                Interceptor interceptor = (Interceptor) ReflectUtils.newInstance(clazz);
                interceptorConfig = new InterceptorConfig();
                interceptorConfig.setName(name);
                interceptorConfig.setInterceptor(interceptor);
                interceptorConfig.setInterceptorClass((Class<? extends Interceptor>) clazz);
                interceptors.add(interceptorConfig);
                log.info("初始化plugin[name={},clazz={}]完毕", name, className);
            }
            log.info("初始化interceptor节点数量{}个", length);
        }
        return sc;
    }

}
